package org.vnl.platform.impl.service.rule;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Node;
import org.vnl.platform.dk.util.Dom4jHelper;
import org.vnl.platform.service.rule.DefaultRuleConfigContainer;
import org.vnl.platform.service.rule.IRuleConfig;
import org.vnl.platform.service.rule.IRuleConfigContainer;
import org.vnl.platform.service.rule.RuleConfigContainerFactory;
import org.vnl.platform.service.rule.RuleErrCode;
import org.vnl.platform.service.rule.RuleRuntimeException;

/**
 * 利用XML設定建立規則設定
 * 
 * <pre>
 * <Rules>
 *   <Owner name="ownerId1">
 *     <Rule name="ruleId1">
 *       <Class name="className1" />
 *       <Class name="className2" />
 *     </Rule>
 *   </Owner>
 *   <Owner name="ownerId2">
 *     <Rule name="ruleId2">
 *       <Class name="className3" />
 *       <Class name="className4" />
 *     </Rule>
 *   </Owner>
 * </Rules>
 * </pre>
 * 
 * @author Vaughan
 *
 */
public class RuleConfigBuilder {
    
    private static Logger logger = Logger.getLogger(RuleConfigBuilder.class);

    private static RuleConfigBuilder instance;
    
    private RuleConfigBuilder() {
        
    }
    
    public static RuleConfigBuilder getInstance() {
        if (instance == null) {
            instance = new RuleConfigBuilder();
        }
        return instance;
    }
    
    public void build(String configXmL) {
        RuleConfigContainerFactory factory = RuleConfigContainerFactory.getInstance();
        IRuleConfigContainer container = factory.getRuleConfigContainer();
        if (container == null) {
            container = new DefaultRuleConfigContainer();
        } else if (!(container instanceof DefaultRuleConfigContainer)) {
            throw new RuleRuntimeException(RuleErrCode.INCOMPATIBLE_RULE_CONFIG_CONTAINER);
        }
        Document doc = Dom4jHelper.getInstance().getDocument(configXmL);
        if (doc == null) {
            throw new RuleRuntimeException(RuleErrCode.LOAD_RULE_CONFIG_ERR);
        }
        List<? extends Node> owners = doc.selectNodes("//Rules/Owner");
        for (Node owner : owners) {
            String ownerId = owner.valueOf("@name");
            if (StringUtils.isBlank(ownerId)) {
                throw new RuleRuntimeException(RuleErrCode.LOAD_RULE_CONFIG_ERR);
            }
            List<? extends Node> rules = doc.selectNodes("Rule");
            for (Node rule : rules) {
                String ruleId = rule.valueOf("@name");
                if (StringUtils.isBlank(ruleId)) {
                    throw new RuleRuntimeException(RuleErrCode.LOAD_RULE_CONFIG_ERR);
                }
                List<? extends Node> classes = doc.selectNodes("Class");
                for (Node clz : classes) {
                    String clzName = clz.valueOf("@name");
                    IRuleConfig config = createConfig(clzName);
                    ((DefaultRuleConfigContainer) container).addRule(ownerId, ruleId, config);
                }
            }
        }
    }

    private IRuleConfig createConfig(String clzName) {
        try {
            Object obj = Class.forName(clzName).newInstance();
            if (obj instanceof IRuleConfig) {
                return (IRuleConfig) obj;
            }
        } catch (InstantiationException e) {
            logger.error("Create Rule Config Fail",e);
        } catch (IllegalAccessException e) {
            logger.error("Create Rule Config Fail",e);
        } catch (ClassNotFoundException e) {
            logger.error("Create Rule Config Fail",e);
        }
        throw new RuleRuntimeException(RuleErrCode.LOAD_RULE_CONFIG_ERR);
    }
}
